﻿#include "base64/base64.h"
#include "http_parser/http_parser.h"
#include "knet/knet.h"
#include "sha1/sha1.h"
#include "../../box/box_channel.hh"
#include "../../box/service_box.hh"
#include "../../detail/box_config_impl.hh"
#include "websocket_impl.hh"

#include <bitset>
#include <limits>
#include <memory>
#include <sstream>
#include <stdexcept>

/**
 * @brief WebSocket帧类型
 */
struct WebSocketFrameType {
  constexpr static std::uint8_t PING_FRAME = 0x19;   ///< ping帧
  constexpr static std::uint8_t PONG_FRAME = 0x1A;   ///< pong帧
  constexpr static std::uint8_t TEXT_FRAME = 0x81;   ///< 文本帧
  constexpr static std::uint8_t BINARY_FRAME = 0x82; ///< 二进制帧
};

struct BoxChannelUserData {
  kratos::unique_pool_ptr<http_parser> parser; ///< HTTP协议解析器
  kratos::unique_pool_ptr<http_parser_settings>
      parser_settings;           ///< HTTP解析器配置
  bool upgrade_finish{false};    ///< 升级是否完成
  std::string sec_websocket_key; ///< Sec-WebSocket-Key
  bool need_key{false};          ///< 是否已经解析到Sec-WebSocket-Key
  std::string sec_websocket_protocol; ///< Sec-WebSocket-Protocol
  bool need_protocol{false}; ///< 是否已经解析到Sec-WebSocket-Protocol
  bool need_upgrade{false};  ///< 是否遇到Connection: Upgrade
  bool is_websocket{false};  ///< 是否已经升级到了Websocket
  kratos::ws::WebSocketServerImpl *server{nullptr}; ///< Websocket服务
  kringbuffer_t *rb{nullptr};        ///< 客户端数据暂存缓冲区
  kratos::ws::BoxChannelPtr channel; ///< 客户端管道
  bool is_clean{false};              ///< 是否已经清理过
  /**
   * @brief 升级完成后清理掉解析器
   */
  void cleanup_after_upgrade() {
    if (!upgrade_finish || is_clean) {
      // 未完成升级或已经清理完成
      return;
    }
    if (parser) {
      parser.reset();
    }
    if (parser_settings) {
      parser_settings.reset();
    }
    is_clean = true;
  }
  void cleanup() {
    cleanup_after_upgrade();
    if (rb) {
      ringbuffer_destroy(rb);
      rb = nullptr;
    }
    server = nullptr;
  }
};

kratos::ws::WebSocketServerImpl::WebSocketServerImpl(ServiceBoxPointer box) {
  box_ = box;
  buffer_ = kratos::make_unique_pool_ptr<char>(BUFFER_LENGTH);
}

kratos::ws::WebSocketServerImpl::~WebSocketServerImpl() {}

auto kratos::ws::WebSocketServerImpl::startup(WebSocketCallback callback)
    -> bool {
  callback_ = callback;
  return service::BoxNetwork::start();
}

auto kratos::ws::WebSocketServerImpl::shutdown() -> bool { return stop(); }

auto kratos::ws::WebSocketServerImpl::get_config()
    -> kratos::config::BoxConfig & {
  if (!box_) {
    static kratos::config::BoxConfigImpl config(nullptr);
    return config;
  }
  return box_->get_config();
}

auto kratos::ws::WebSocketServerImpl::get_logger_appender()
    -> klogger::Appender * {
  return box_->get_logger_appender();
}

auto kratos::ws::WebSocketServerImpl::get_lang() -> lang::Lang * {
  return box_->get_lang();
}

void kratos::ws::WebSocketServerImpl::on_listen(const std::string &name,
                                                bool success,
                                                BoxChannelPtr &channel) {
  return;
}

void kratos::ws::WebSocketServerImpl::on_accept(BoxChannelPtr &channel) {
  // 建立用户数据
  auto *user_data = kratos::allocate<BoxChannelUserData>();
  user_data->server = this;
  user_data->rb = ringbuffer_create(RINGBUFFER_INIT_LENGTH);
  user_data->parser = kratos::make_unique_pool_ptr<http_parser>();
  user_data->parser_settings =
      kratos::make_unique_pool_ptr<http_parser_settings>();
  user_data->channel = channel;
  // 初始化HTTP协议解析器
  http_parser_init(user_data->parser.get(), HTTP_REQUEST);
  user_data->parser->data = user_data;
  // HTTP协议解析器回调设置
  auto *settings = user_data->parser_settings.get();
  setup_http_parser_settings(settings);
  // 设置用户数据
  channel->set_user_data((std::uint64_t)user_data);
  // 建立Websocket管道
  auto websocket_channel =
      kratos::make_shared_pool_ptr<WebSocketChannelImpl>(user_data);
  // 设置真正的管道ID到WebSocket管道
  websocket_channel->set_id(channel->get_id());
  websocket_channel_map_[channel->get_id()] = websocket_channel;
}

void kratos::ws::WebSocketServerImpl::on_connect(const std::string &name,
                                                 bool success,
                                                 BoxChannelPtr &channel) {
  throw std::runtime_error("Not supported");
}

void kratos::ws::WebSocketServerImpl::on_close(BoxChannelPtr &channel) {
  auto it = websocket_channel_map_.find(channel->get_id());
  if (it != websocket_channel_map_.end()) {
    // 调用用户回调
    call_cb(WebSocketEvent::CLOSE, it->second);
    websocket_channel_map_.erase(it);
  }
  auto *user_data = channel->cast_user_data<BoxChannelUserData *>();
  if (user_data) {
    user_data->cleanup();
    kratos::box_dispose(user_data);
  }
  channel->set_user_data(0);
}

void kratos::ws::WebSocketServerImpl::on_data(BoxChannelPtr &channel) {
  auto *user_data = channel->cast_user_data<BoxChannelUserData *>();
  if (!user_data) {
    channel->close();
    return;
  }
  if (!user_data->upgrade_finish) {
    // 还未完成升级, 写入临时缓冲区进行解析
    auto recv_bytes = channel->recv(buffer_.get(), channel->size());
    if (recv_bytes <= 0) {
      // 接收失败
      channel->close();
      return;
    }

    auto parsed_bytes = http_parser_execute(user_data->parser.get(),
                                            user_data->parser_settings.get(),
                                            buffer_.get(), recv_bytes);
    if (recv_bytes != (int)parsed_bytes) {
      // 接收的字节数量不匹配, 关闭
      channel->close();
      return;
    }
  } else {
    // 检查并清理
    user_data->cleanup_after_upgrade();
    // 已经升级到Websocket, 按帧接收数据
    auto status = FrameStatus::CONT;
    while (status != FrameStatus::EXIT) {
      status = try_get_data(channel, user_data);
      if (status == FrameStatus::PACKET) {
        // 处理协议,协议已经在缓冲区内了, 调用用户回调
        auto websocket_channel = from_box_channel(channel);
        if (websocket_channel) {
          call_cb(WebSocketEvent::RECV, websocket_channel);
        } else {
          channel->close();
        }
      }
    }
  }
}

auto kratos::ws::WebSocketServerImpl::get_channel(std::uint64_t channel_id)
    -> WebSocketChannelPtr {
  auto it = websocket_channel_map_.find(channel_id);
  if (it == websocket_channel_map_.end()) {
    return nullptr;
  }
  return it->second;
}

auto kratos::ws::WebSocketServerImpl::return_handshake(
    BoxChannelPtr &channel, BoxChannelUserData *user_data) -> void {
  std::stringstream ss;
  ss << "HTTP/1.1 101 Switching Protocols\r\n";
  ss << "Upgrade: WebSocket\r\n";
  ss << "Connection: Upgrade\r\n";
  if (!user_data->sec_websocket_key.empty()) {
    std::uint8_t digest[20];
    // RFC6455规定的key
    std::string return_key =
        user_data->sec_websocket_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    // sha1
    SHA1 sha;
    sha.Input(return_key.data(), (unsigned)return_key.size());
    sha.Result(reinterpret_cast<unsigned int *>(digest));
    for (std::size_t i = 0; i < sizeof(digest); i += 4) {
      std::uint8_t c;
      c = digest[i];
      digest[i] = digest[i + 3];
      digest[i + 3] = c;
      c = digest[i + 1];
      digest[i + 1] = digest[i + 2];
      digest[i + 2] = c;
    }
    // base64
    return_key = base64_encode(digest, sizeof(digest));
    ss << "Sec-WebSocket-Accept: " << return_key << "\r\n";
  }
  if (!user_data->sec_websocket_protocol.empty()) {
    ss << "Sec-WebSocket-Protocol: " << user_data->sec_websocket_protocol
       << "\r\n";
  }
  ss << "\r\n";
  auto return_string = ss.str();
  channel->send(return_string.data(), (int)return_string.size());
  // 调用用户回调, 连接建立完成
  call_cb(WebSocketEvent::ACCEPT, from_box_channel(channel));
}

auto kratos::ws::WebSocketServerImpl::return_pong(BoxChannelPtr &channel) {
  int pos = 0;
  auto *buffer = buffer_.get();
  buffer[pos++] = WebSocketFrameType::PONG_FRAME;
  // 发送
  return channel->send(buffer, pos);
}

auto kratos::ws::WebSocketServerImpl::fill_frame_header_length(char *buffer,
                                                               int &pos,
                                                               int size)
    -> void {
  /*
   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-------+-+-------------+-------------------------------+
  |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
  |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
  |N|V|V|V|       |S|             |   (if payload len==126/127)   |
  | |1|2|3|       |K|             |                               |
  +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  |     Extended payload length continued, if payload len == 127  |
  + - - - - - - - - - - - - - - - +-------------------------------+
  |                               |Masking-key, if MASK set to 1  |
  +-------------------------------+-------------------------------+
  | Masking-key (continued)       |          Payload Data         |
  +-------------------------------- - - - - - - - - - - - - - - - +
  :                     Payload Data continued ...                :
  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  |                     Payload Data continued ...                |
  +---------------------------------------------------------------+
  */
  if (size <= LENGTH_GAP) {
    buffer[pos++] = size;
  } else if (size <= EXTEND_GAP) {
    buffer[pos++] = BIT_16_LENGTH_FLAG;
    auto *length_buffer = reinterpret_cast<std::uint16_t *>(buffer + pos);
    *length_buffer = htons((std::uint16_t)size);
    pos += LENGTH_BYTE;
  } else {
    buffer[pos++] = BIT_64_LENGTH_FLAG;
    auto *length_buffer = reinterpret_cast<std::uint64_t *>(buffer + pos);
    *length_buffer = htonll(size);
    pos += EXTEND_BYTE;
  }
}

auto kratos::ws::WebSocketServerImpl::fill_data_frame_type(char *buffer,
                                                           int &pos,
                                                           std::uint8_t type)
    -> void {
  buffer[pos++] = type;
}

auto kratos::ws::WebSocketServerImpl::send(BoxChannelPtr &channel,
                                           const char *data, int size,
                                           bool is_binary) -> int {
  int pos = 0;
  auto *buffer = buffer_.get();
  if (is_binary) {
    // 按照二进制帧发送
    fill_data_frame_type(buffer, pos, WebSocketFrameType::BINARY_FRAME);
  } else {
    // 按照文本帧发送
    fill_data_frame_type(buffer, pos, WebSocketFrameType::TEXT_FRAME);
  }
  // 根据发送长度计算帧长度头
  fill_frame_header_length(buffer, pos, size);
  // 返回给客户端的数据不需要用掩码加密
  if (data) {
    memcpy(buffer + pos, data, size);
  }
  // 发送
  return channel->send(buffer, pos + size);
}

auto kratos::ws::WebSocketServerImpl::get_opcode(char byte) -> int {
  return (byte & 0xf);
}

auto kratos::ws::WebSocketServerImpl::get_fin(char byte) -> bool {
  return std::bitset<8>(byte).test(0);
}

auto kratos::ws::WebSocketServerImpl::get_mask(char byte) -> bool {
  return std::bitset<8>(byte).test(7);
}

auto kratos::ws::WebSocketServerImpl::get_basic_length(char byte) -> int {
  return byte & 0x7f;
}

auto kratos::ws::WebSocketServerImpl::get_extend_length_basic(char *buffer)
    -> int {
  std::bitset<LENGTH_BYTE * 8> bit16_32(*(std::int16_t *)(buffer));
  return ntohs((std::uint16_t)bit16_32.to_ulong());
}

auto kratos::ws::WebSocketServerImpl::get_extend_length(char *buffer)
    -> std::uint64_t {
  std::bitset<EXTEND_BYTE * 8> bit16_80(*(std::uint64_t *)(buffer));
  return knet_ntohll(bit16_80.to_ullong());
}

auto kratos::ws::WebSocketServerImpl::get_mask_key(char *buffer)
    -> std::uint32_t {
  std::bitset<32> bit32(*(std::uint32_t *)(buffer));
  return bit32.to_ulong();
}

auto kratos::ws::WebSocketServerImpl::unmask_payload(std::uint32_t mask_key,
                                                     char *buffer,
                                                     std::uint64_t length)
    -> void {
  const auto *mask_char = reinterpret_cast<char *>(&mask_key);
  for (std::uint64_t i = 0; i < length; i++) {
    buffer[i] = buffer[i] ^ mask_char[i % 4];
  }
}

auto kratos::ws::WebSocketServerImpl::parse_header(
    BoxChannelPtr &channel, bool &fin, int &opcode, std::size_t &payload_pos,
    std::uint64_t &length, std::uint32_t &mask_key) -> bool {
  // 管道内数据总长度
  auto size = channel->size();
  if (size < HEADER_BASIC_BYTE) {
    return false;
  }
  auto *buffer = buffer_.get();
  // 将所有数据写入缓冲区，但不从管道内移除
  channel->peek(buffer, HEADER_BASIC_BYTE);
  opcode = get_opcode(buffer[0]);
  if (opcode == OPCODE::CLOSE) {
    // 对端要求断开连接
    channel->close();
    return false;
  }
  fin = get_fin(buffer[0]);
  auto mask = get_mask(buffer[1]);
  length = get_basic_length(buffer[1]);
  payload_pos = HEADER_BASIC_BYTE;
  if (length == BIT_16_LENGTH_FLAG) {
    if (size < HEADER_LENGTH_BYTE) {
      return false;
    }
    channel->peek(buffer, HEADER_LENGTH_BYTE);
    length = get_extend_length_basic(buffer + HEADER_BASIC_BYTE);
    // Extended payload length, 2 bytes
    payload_pos += LENGTH_BYTE;
  } else if (length == BIT_64_LENGTH_FLAG) {
    // Extended payload length, 8 bytes
    if (size < HEADER_EXTEND_LENGTH_BYTE) {
      return false;
    }
    channel->peek(buffer, HEADER_EXTEND_LENGTH_BYTE);
    length = get_extend_length(buffer + HEADER_BASIC_BYTE);
    payload_pos += EXTEND_BYTE;
  }
  if (mask) {
    if (length + payload_pos + std::size_t(MASK_BYTE) > std::size_t(size)) {
      return false;
    }
    channel->peek(buffer, HEADER_MASK_BYTE);
    mask_key = get_mask_key(buffer + payload_pos);
    // skip mask
    payload_pos += MASK_BYTE;
  }
  if (length + payload_pos > std::size_t(size)) {
    return false;
  }
  return true;
}

auto kratos::ws::WebSocketServerImpl::parser_header_after_phase(
    BoxChannelPtr &channel, BoxChannelUserData *user_data, bool fin, int opcode,
    std::uint64_t length) -> FrameStatus {
  switch (opcode) {
  case OPCODE::SLICE_FRAME:  // 分片的数据帧
  case OPCODE::TEXT_FRAME:   // 文本帧
  case OPCODE::BINARY_FRAME: // 二进制帧
    if (length) {
      ringbuffer_write(user_data->rb, buffer_.get(), (std::uint32_t)length);
    }
    // 检测是否是最后一个fragment
    if (fin) {
      return FrameStatus::PACKET;
    } else {
      return FrameStatus::CONT;
    }
    break;
  case OPCODE::PING: // PING
    // 回复心跳
    return_pong(channel);
    return FrameStatus::CONT;
  case OPCODE::PONG: // PONG
    return FrameStatus::CONT;
  default:
    // 其他的控制命令全部视为无效
    channel->close();
    return FrameStatus::EXIT;
  }
  return FrameStatus::CONT;
}

auto kratos::ws::WebSocketServerImpl::try_get_data(
    BoxChannelPtr &channel, BoxChannelUserData *user_data) -> FrameStatus {
  /*
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-------+-+-------------+-------------------------------+
   |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
   |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
   |N|V|V|V|       |S|             |   (if payload len==126/127)   |
   | |1|2|3|       |K|             |                               |
   +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
   |     Extended payload length continued, if payload len == 127  |
   + - - - - - - - - - - - - - - - +-------------------------------+
   |                               |Masking-key, if MASK set to 1  |
   +-------------------------------+-------------------------------+
   | Masking-key (continued)       |          Payload Data         |
   +-------------------------------- - - - - - - - - - - - - - - - +
   :                     Payload Data continued ...                :
   + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
   |                     Payload Data continued ...                |
   +---------------------------------------------------------------+
   */
  bool fin = false;
  int opcode = -1;
  std::size_t payload_pos = 0;
  std::uint64_t length = 0;
  std::uint32_t mask_key = 0;
  if (!parse_header(channel, fin, opcode, payload_pos, length, mask_key)) {
    return FrameStatus::EXIT;
  }
  channel->skip((int)payload_pos);
  channel->recv(buffer_.get(), (int)length);
  if (mask_key) {
    // 掩码解密
    unmask_payload(mask_key, buffer_.get(), length);
  }
  return parser_header_after_phase(channel, user_data, fin, opcode, length);
}

int kratos::ws::WebSocketServerImpl::on_message_complete(http_parser *parser) {
  auto *user_data = (BoxChannelUserData *)parser->data;
  if (!user_data) {
    return 0;
  }
  if (user_data->is_websocket) {
    // 升级完成，发送握手
    user_data->upgrade_finish = true;
    user_data->server->return_handshake(user_data->channel, user_data);
  } else {
    // 没有完成升级或者是一个错误的连接
    user_data->channel->close();
  }
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_header_field(http_parser *parser,
                                                     const char *at,
                                                     std::size_t length) {
  auto *user_data = (BoxChannelUserData *)parser->data;
  if (!user_data) {
    return 0;
  }
  std::string header_key(at, length);
  if (header_key == "Sec-WebSocket-Key") {
    user_data->need_key = true;
  } else if (header_key == "Sec-WebSocket-Protocol") {
    user_data->need_protocol = true;
  } else if (header_key == "Connection") {
    user_data->need_upgrade = true;
  }
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_header_value(http_parser *parser,
                                                     const char *at,
                                                     std::size_t length) {
  auto *user_data = (BoxChannelUserData *)parser->data;
  if (!user_data) {
    return 0;
  }
  std::string header_value(at, length);
  if (user_data->need_key && user_data->sec_websocket_key.empty()) {
    user_data->sec_websocket_key.assign(at, length);
  } else if (user_data->need_protocol &&
             user_data->sec_websocket_protocol.empty()) {
    user_data->sec_websocket_protocol.assign(at, length);
  } else if (user_data->need_upgrade) {
    user_data->need_upgrade = false;
    if (header_value == "Upgrade") {
      user_data->is_websocket = true;
    }
  }
  return 0;
}

auto kratos::ws::WebSocketServerImpl::setup_http_parser_settings(
    http_parser_settings *settings) -> void {
  settings->on_body = &WebSocketServerImpl::on_body;
  settings->on_chunk_complete = &WebSocketServerImpl::on_chunk_complete;
  settings->on_chunk_header = &WebSocketServerImpl::on_chunk_header;
  settings->on_headers_complete = &WebSocketServerImpl::on_headers_complete;
  settings->on_header_field = &WebSocketServerImpl::on_header_field;
  settings->on_header_value = &WebSocketServerImpl::on_header_value;
  settings->on_message_begin = &WebSocketServerImpl::on_message_begin;
  settings->on_message_complete = &WebSocketServerImpl::on_message_complete;
  settings->on_status = &WebSocketServerImpl::on_status;
  settings->on_url = &WebSocketServerImpl::on_url;
}

auto kratos::ws::WebSocketServerImpl::call_cb(WebSocketEvent e,
                                              WebSocketChannelPtr channel)
    -> void {
  if (callback_ && channel) {
    callback_(e, channel);
  }
}

auto kratos::ws::WebSocketServerImpl::from_box_channel(
    BoxChannelPtr box_channel) -> WebSocketChannelPtr {
  auto it = websocket_channel_map_.find(box_channel->get_id());
  if (it == websocket_channel_map_.end()) {
    return nullptr;
  }
  return it->second;
}

kratos::ws::WebSocketChannelImpl::WebSocketChannelImpl(
    BoxChannelUserData *user_data) {
  user_data_ = user_data;
}

kratos::ws::WebSocketChannelImpl::~WebSocketChannelImpl() {}

int kratos::ws::WebSocketChannelImpl::send(const char *data, const int size) {
  return user_data_->server->send(user_data_->channel, data, size, true);
}

int kratos::ws::WebSocketChannelImpl::peek(char *data, const int size) {
  if (isClose()) {
    return 0;
  }
  if (!data || !size) {
    return 0;
  }
  return ringbuffer_copy(user_data_->rb, data, size);
}

int kratos::ws::WebSocketChannelImpl::recv(char *data, const int size) {
  if (isClose()) {
    return 0;
  }
  if (!data || !size) {
    return 0;
  }
  return ringbuffer_read(user_data_->rb, data, size);
}

int kratos::ws::WebSocketChannelImpl::skip(const int size) {
  if (isClose()) {
    return 0;
  }
  if (!size) {
    return 0;
  }
  if (error_ok == ringbuffer_eat(user_data_->rb, size)) {
    return size;
  }
  return 0;
}

int kratos::ws::WebSocketChannelImpl::size() {
  if (isClose()) {
    return 0;
  }
  return ringbuffer_available(user_data_->rb);
}

bool kratos::ws::WebSocketChannelImpl::isClose() {
  return user_data_->channel->isClose();
}

void kratos::ws::WebSocketChannelImpl::close() { user_data_->channel->close(); }

auto kratos::ws::WebSocketChannelImpl::send(const std::string &data) -> int {
  return user_data_->server->send(user_data_->channel, data.data(),
                                  (int)data.size(), false);
}

auto kratos::ws::WebSocketChannelImpl::recv(std::string &str) -> int {
  auto length = size();
  if (buffer_size_ < length) {
    buffer_.reset();
    buffer_ = kratos::make_unique_pool_ptr<char>(length);
    buffer_size_ = length;
  }
  if (recv(buffer_.get(), length) != length) {
    return 0;
  }
  str.assign(buffer_.get(), length);
  return length;
}

auto kratos::ws::WebSocketChannelImpl::get_id()->std::uint64_t {
  return id_;
}

auto kratos::ws::WebSocketChannelImpl::set_id(std::uint64_t id) -> void {
  id_ = id;
}

int kratos::ws::WebSocketServerImpl::on_message_begin(http_parser *) {
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_url(http_parser *, const char *,
                                            std::size_t) {
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_status(http_parser *, const char *,
                                               std::size_t) {
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_headers_complete(http_parser *) {
  return 2;
}

int kratos::ws::WebSocketServerImpl::on_body(http_parser *, const char *,
                                             std::size_t) {
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_chunk_header(http_parser *) {
  return 0;
}

int kratos::ws::WebSocketServerImpl::on_chunk_complete(http_parser *) {
  return 0;
}
